package com.kylin.upms.biz.common.springSecurity;

import com.alibaba.fastjson.JSON;
import com.kylin.upms.biz.service.impl.UserServiceImpl;
import com.kylin.common.result.ResEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;



@Configuration
@EnableGlobalMethodSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserServiceImpl userService;

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    KylinAccessDecisionVoter kylinAccessDecisionVoter;


    @Autowired
    KylinFilterInvocationSecurityMetadataSource kylinFilterInvocationSecurityMetadataSource;
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers("/login_p");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>(){
            @Override
            public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                o.setSecurityMetadataSource(kylinFilterInvocationSecurityMetadataSource);
                o.setAccessDecisionManager(kylinAccessDecisionVoter);
                return o;
            }
        }).antMatchers("/login_p").permitAll().anyRequest().authenticated().and()
                .formLogin().loginPage("/login_p").successHandler(new AuthenticationSuccessHandler(){
            @Override
            public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter writer = httpServletResponse.getWriter();
                writer.write(JSON.toJSONString(ResEntity.ok("登陆成功",SecurityContextHolder.getContext().getAuthentication().getPrincipal())));
                writer.flush();
                writer.close();
            }
        }).failureHandler(new AuthenticationFailureHandler(){

            @Override
            public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter writer = httpServletResponse.getWriter();

                ResEntity entity = null;
                if (e instanceof UsernameNotFoundException){
                    entity  = ResEntity.error("用户名不存在");
                }else if (e instanceof LockedException){
                    entity  = ResEntity.error("用户被锁定");
                }else if (e instanceof AccountExpiredException){
                    entity  = ResEntity.error("账号过期");
                }else if(e instanceof CredentialsExpiredException){
                    entity = ResEntity.error("密码过期");
                }else if(e instanceof BadCredentialsException){
                    entity = ResEntity.error("密码输入不正确");
                }
                else {
                    entity = ResEntity.error("登陆失败");
                }
                writer.write(JSON.toJSONString(entity));
                writer.flush();
                writer.close();
            }
        }).loginProcessingUrl("/login").permitAll().and().exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
            @Override
            public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
                httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
                logger.info(e.getMessage());
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter writer = httpServletResponse.getWriter();
                writer.write(JSON.toJSONString(ResEntity.error(e.getMessage())));
                writer.flush();
                writer.close();

            }
        }).and().cors().configurationSource(CorsConfigurationSource()).and().csrf().disable();
    }

    //配置跨域访问资源
    @Bean
    public CorsConfigurationSource CorsConfigurationSource() {
        CorsConfigurationSource source =   new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://localhost:8080");   //同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
        corsConfiguration.addAllowedHeader("*");//header，允许哪些header，本案中使用的是token，此处可将*替换为token；
        corsConfiguration.addAllowedMethod("*");   //允许的请求方法，PSOT、GET等
        corsConfiguration.setAllowCredentials(true);
        ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**",corsConfiguration); //配置允许跨域访问的url
        return source;
    }
}
